// ============================================
// internal/service/storage_pool_service.go
// ============================================

package service

import (
	"context"
	"fmt"
	"time"

	"github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
	"libvirt.org/go/libvirtxml"

	"virt-manager-go/internal/domain"
)

type storagePoolService struct {
	connMgr domain.ConnectionManager
	logger  *logrus.Logger
}

func NewStoragePoolService(connMgr domain.ConnectionManager, logger *logrus.Logger) domain.StoragePoolService {
	return &storagePoolService{
		connMgr: connMgr,
		logger:  logger,
	}
}

// ListPools 列出所有存储池
func (s *storagePoolService) ListPools(ctx context.Context, connID string) ([]*domain.StoragePoolInfo, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	pools, err := conn.ListAllStoragePools(libvirt.CONNECT_LIST_STORAGE_POOLS_ACTIVE | libvirt.CONNECT_LIST_STORAGE_POOLS_INACTIVE)
	if err != nil {
		return nil, fmt.Errorf("failed to list storage pools: %w", err)
	}

	poolInfos := make([]*domain.StoragePoolInfo, 0, len(pools))
	for _, pool := range pools {
		poolInfo, err := s.poolToInfo(&pool)
		pool.Free()
		if err != nil {
			s.logger.WithError(err).Warn("Failed to convert pool to info")
			continue
		}
		poolInfos = append(poolInfos, poolInfo)
	}

	return poolInfos, nil
}

// GetPool 获取存储池信息
func (s *storagePoolService) GetPool(ctx context.Context, connID, poolName string) (*domain.StoragePoolInfo, error) {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return nil, err
	}
	defer pool.Free()

	return s.poolToInfo(pool)
}

// CreatePool 创建存储池
func (s *storagePoolService) CreatePool(ctx context.Context, connID string, config *domain.StoragePoolConfig) (*domain.StoragePoolInfo, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"pool_name":  config.Name,
		"pool_type":  config.Type,
	}).Info("Creating storage pool")

	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	// 构建存储池 XML
	xmlData, err := s.buildPoolXML(config)
	if err != nil {
		return nil, fmt.Errorf("failed to build pool XML: %w", err)
	}

	s.logger.WithField("xml", xmlData).Debug("Generated pool XML")

	// 定义存储池
	pool, err := conn.StoragePoolDefineXML(xmlData, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to define storage pool: %w", err)
	}
	defer pool.Free()

	// 构建存储池（创建目录等）
	if err := pool.Build(libvirt.STORAGE_POOL_BUILD_NEW); err != nil {
		s.logger.WithError(err).Warn("Failed to build pool, may already exist")
	}

	// 启动存储池
	if err := pool.Create(0); err != nil {
		return nil, fmt.Errorf("failed to start storage pool: %w", err)
	}

	// 设置自动启动
	if config.Autostart {
		if err := pool.SetAutostart(true); err != nil {
			s.logger.WithError(err).Warn("Failed to set autostart")
		}
	}

	s.logger.WithField("pool_name", config.Name).Info("Storage pool created successfully")

	return s.poolToInfo(pool)
}

// DeletePool 删除存储池
func (s *storagePoolService) DeletePool(ctx context.Context, connID, poolName string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	// 检查是否活跃
	active, err := pool.IsActive()
	if err != nil {
		return fmt.Errorf("failed to check pool state: %w", err)
	}

	// 如果活跃，先停止
	if active {
		if err := pool.Destroy(); err != nil {
			return fmt.Errorf("failed to stop pool: %w", err)
		}
	}

	// 删除存储池（可选：删除物理存储）
	if err := pool.Delete(libvirt.STORAGE_POOL_DELETE_NORMAL); err != nil {
		s.logger.WithError(err).Warn("Failed to delete pool storage")
	}

	// 取消定义
	if err := pool.Undefine(); err != nil {
		return fmt.Errorf("failed to undefine pool: %w", err)
	}

	s.logger.WithField("pool_name", poolName).Info("Storage pool deleted")
	return nil
}

// StartPool 启动存储池
func (s *storagePoolService) StartPool(ctx context.Context, connID, poolName string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	if err := pool.Create(0); err != nil {
		return fmt.Errorf("failed to start pool: %w", err)
	}

	s.logger.WithField("pool_name", poolName).Info("Storage pool started")
	return nil
}

// StopPool 停止存储池
func (s *storagePoolService) StopPool(ctx context.Context, connID, poolName string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	if err := pool.Destroy(); err != nil {
		return fmt.Errorf("failed to stop pool: %w", err)
	}

	s.logger.WithField("pool_name", poolName).Info("Storage pool stopped")
	return nil
}

// RefreshPool 刷新存储池
func (s *storagePoolService) RefreshPool(ctx context.Context, connID, poolName string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	if err := pool.Refresh(0); err != nil {
		return fmt.Errorf("failed to refresh pool: %w", err)
	}

	s.logger.WithField("pool_name", poolName).Info("Storage pool refreshed")
	return nil
}

// SetAutostart 设置自动启动
func (s *storagePoolService) SetAutostart(ctx context.Context, connID, poolName string, autostart bool) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	if err := pool.SetAutostart(autostart); err != nil {
		return fmt.Errorf("failed to set autostart: %w", err)
	}

	return nil
}

// ListVolumes 列出存储卷
func (s *storagePoolService) ListVolumes(ctx context.Context, connID, poolName string) ([]*domain.StorageVolumeInfo, error) {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return nil, err
	}
	defer pool.Free()

	volumes, err := pool.ListAllStorageVolumes(0)
	if err != nil {
		return nil, fmt.Errorf("failed to list volumes: %w", err)
	}

	volumeInfos := make([]*domain.StorageVolumeInfo, 0, len(volumes))
	for _, vol := range volumes {
		volInfo, err := s.volumeToInfo(&vol)
		vol.Free()
		if err != nil {
			s.logger.WithError(err).Warn("Failed to convert volume to info")
			continue
		}
		volumeInfos = append(volumeInfos, volInfo)
	}

	return volumeInfos, nil
}

// GetVolume 获取存储卷信息
func (s *storagePoolService) GetVolume(ctx context.Context, connID, poolName, volumeName string) (*domain.StorageVolumeInfo, error) {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return nil, err
	}
	defer pool.Free()

	vol, err := pool.LookupStorageVolByName(volumeName)
	if err != nil {
		return nil, fmt.Errorf("failed to lookup volume: %w", err)
	}
	defer vol.Free()

	return s.volumeToInfo(vol)
}

// CreateVolume 创建存储卷
func (s *storagePoolService) CreateVolume(ctx context.Context, connID, poolName string, config *domain.StorageVolumeConfig) (*domain.StorageVolumeInfo, error) {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return nil, err
	}
	defer pool.Free()

	// 构建卷 XML
	xmlData, err := s.buildVolumeXML(config)
	if err != nil {
		return nil, fmt.Errorf("failed to build volume XML: %w", err)
	}

	// 创建卷
	vol, err := pool.StorageVolCreateXML(xmlData, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to create volume: %w", err)
	}
	defer vol.Free()

	s.logger.WithFields(logrus.Fields{
		"pool":   poolName,
		"volume": config.Name,
	}).Info("Storage volume created")

	return s.volumeToInfo(vol)
}

// CloneVolume 克隆存储卷
func (s *storagePoolService) CloneVolume(ctx context.Context, connID, poolName, srcVolume, destVolume string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	// 获取源卷
	srcVol, err := pool.LookupStorageVolByName(srcVolume)
	if err != nil {
		return fmt.Errorf("source volume not found: %w", err)
	}
	defer srcVol.Free()

	// 获取源卷 XML 并修改名称
	srcXML, err := srcVol.GetXMLDesc(0)
	if err != nil {
		return fmt.Errorf("failed to get source volume XML: %w", err)
	}

	volConfig := &libvirtxml.StorageVolume{}
	if err := volConfig.Unmarshal(srcXML); err != nil {
		return fmt.Errorf("failed to parse volume XML: %w", err)
	}

	volConfig.Name = destVolume
	volConfig.Key = ""

	destXML, err := volConfig.Marshal()
	if err != nil {
		return fmt.Errorf("failed to marshal volume XML: %w", err)
	}

	// 克隆卷
	destVol, err := pool.StorageVolCreateXMLFrom(destXML, srcVol, 0)
	if err != nil {
		return fmt.Errorf("failed to clone volume: %w", err)
	}
	defer destVol.Free()

	s.logger.WithFields(logrus.Fields{
		"pool":   poolName,
		"source": srcVolume,
		"dest":   destVolume,
	}).Info("Storage volume cloned")

	return nil
}

// DeleteVolume 删除存储卷
func (s *storagePoolService) DeleteVolume(ctx context.Context, connID, poolName, volumeName string) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	vol, err := pool.LookupStorageVolByName(volumeName)
	if err != nil {
		return fmt.Errorf("volume not found: %w", err)
	}
	defer vol.Free()

	if err := vol.Delete(0); err != nil {
		return fmt.Errorf("failed to delete volume: %w", err)
	}

	s.logger.WithFields(logrus.Fields{
		"pool":   poolName,
		"volume": volumeName,
	}).Info("Storage volume deleted")

	return nil
}

// ResizeVolume 调整存储卷大小
func (s *storagePoolService) ResizeVolume(ctx context.Context, connID, poolName, volumeName string, newSize uint64) error {
	pool, err := s.getPool(connID, poolName)
	if err != nil {
		return err
	}
	defer pool.Free()

	vol, err := pool.LookupStorageVolByName(volumeName)
	if err != nil {
		return fmt.Errorf("volume not found: %w", err)
	}
	defer vol.Free()

	if err := vol.Resize(newSize, 0); err != nil {
		return fmt.Errorf("failed to resize volume: %w", err)
	}

	s.logger.WithFields(logrus.Fields{
		"pool":     poolName,
		"volume":   volumeName,
		"new_size": newSize,
	}).Info("Storage volume resized")

	return nil
}

// === 辅助方法 ===

func (s *storagePoolService) getPool(connID, poolName string) (*libvirt.StoragePool, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	pool, err := conn.LookupStoragePoolByName(poolName)
	if err != nil {
		return nil, fmt.Errorf("storage pool not found: %w", err)
	}

	return pool, nil
}

func (s *storagePoolService) poolToInfo(pool *libvirt.StoragePool) (*domain.StoragePoolInfo, error) {
	name, err := pool.GetName()
	if err != nil {
		return nil, err
	}

	uuid, err := pool.GetUUIDString()
	if err != nil {
		return nil, err
	}

	info, err := pool.GetInfo()
	if err != nil {
		return nil, err
	}

	autostart, _ := pool.GetAutostart()
	persistent, _ := pool.IsPersistent()

	// 获取存储池路径
	xmlData, _ := pool.GetXMLDesc(0)
	poolConfig := &libvirtxml.StoragePool{}
	var path string
	if xmlData != "" && poolConfig.Unmarshal(xmlData) == nil && poolConfig.Target != nil {
		path = poolConfig.Target.Path
	}

	// 计算卷数量
	volumes, _ := pool.ListAllStorageVolumes(0)
	volumeCount := len(volumes)
	for _, vol := range volumes {
		vol.Free()
	}

	return &domain.StoragePoolInfo{
		Name:       name,
		UUID:       uuid,
		State:      s.libvirtPoolStateToState(libvirt.StoragePoolState(info.State)),
		Capacity:   info.Capacity,
		Allocation: info.Allocation,
		Available:  info.Available,
		Autostart:  autostart,
		Persistent: persistent,
		Path:       path,
		Volumes:    volumeCount,
		CreatedAt:  time.Now(),
	}, nil
}

func (s *storagePoolService) libvirtPoolStateToState(state libvirt.StoragePoolState) domain.StoragePoolState {
	switch state {
	case libvirt.STORAGE_POOL_INACTIVE:
		return domain.PoolStateInactive
	case libvirt.STORAGE_POOL_BUILDING:
		return domain.PoolStateBuilding
	case libvirt.STORAGE_POOL_RUNNING:
		return domain.PoolStateRunning
	case libvirt.STORAGE_POOL_DEGRADED:
		return domain.PoolStateDegraded
	case libvirt.STORAGE_POOL_INACCESSIBLE:
		return domain.PoolStateInaccessible
	default:
		return domain.PoolStateInactive
	}
}

func (s *storagePoolService) volumeToInfo(vol *libvirt.StorageVol) (*domain.StorageVolumeInfo, error) {
	name, err := vol.GetName()
	if err != nil {
		return nil, err
	}

	key, _ := vol.GetKey()
	path, _ := vol.GetPath()

	info, err := vol.GetInfo()
	if err != nil {
		return nil, err
	}

	return &domain.StorageVolumeInfo{
		Name:       name,
		Key:        key,
		Path:       path,
		Type:       domain.VolumeTypeFile,
		Capacity:   info.Capacity,
		Allocation: info.Allocation,
		CreatedAt:  time.Now(),
	}, nil
}

func (s *storagePoolService) buildPoolXML(config *domain.StoragePoolConfig) (string, error) {
	poolConfig := &libvirtxml.StoragePool{
		Type: config.Type,
		Name: config.Name,
	}

	if config.Target != nil {
		poolConfig.Target = &libvirtxml.StoragePoolTarget{
			Path: config.Target.Path,
		}
	}

	if config.Source != nil {
		poolConfig.Source = &libvirtxml.StoragePoolSource{}
		if config.Source.Host != "" {
			poolConfig.Source.Host = []libvirtxml.StoragePoolSourceHost{
				{Name: config.Source.Host},
			}
		}
		if config.Source.Dir != "" {
			poolConfig.Source.Dir = &libvirtxml.StoragePoolSourceDir{
				Path: config.Source.Dir,
			}
		}
	}

	return poolConfig.Marshal()
}

func (s *storagePoolService) buildVolumeXML(config *domain.StorageVolumeConfig) (string, error) {
	if config.Format == "" {
		config.Format = "qcow2"
	}

	volConfig := &libvirtxml.StorageVolume{
		Type: "file",
		Name: config.Name,
		Capacity: &libvirtxml.StorageVolumeSize{
			Value: config.Capacity,
			Unit:  "B",
		},
		Target: &libvirtxml.StorageVolumeTarget{
			Format: &libvirtxml.StorageVolumeTargetFormat{
				Type: config.Format,
			},
		},
	}

	if config.Allocation > 0 {
		volConfig.Allocation = &libvirtxml.StorageVolumeSize{
			Value: config.Allocation,
			Unit:  "B",
		}
	}

	return volConfig.Marshal()
}
